/*
  Copyright (c) 2000, Al Sutton (al@alsutton.com)
  All rights reserved.
  Redistribution and use in source and binary forms, with or without modification, are permitted
  provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions
  and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of
  conditions and the following disclaimer in the documentation and/or other materials provided with
  the distribution.

  Neither the name of Al Sutton nor the names of its contributors may be used to endorse or promote
  products derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package edu.mobbuzz.messaging;

/**
 * Description:  Class to connects to a server,
 */

import java.io.IOException;
import java.util.Enumeration;

import com.alsutton.jabber.JabberDataBlock;
import com.alsutton.jabber.JabberListener;
import com.alsutton.jabber.JabberStream;
import com.alsutton.jabber.seConnector;
import com.alsutton.jabber.block.Iq;
import com.alsutton.jabber.block.Login;
import com.alsutton.jabber.block.Message;
import com.alsutton.jabber.block.Presence;
import com.alsutton.jabber.block.Register;

import edu.mobbuzz.daf.facade.RssFacade;
import edu.mobbuzz.daf.facade.SubscriberFacade;
import edu.mobbuzz.daf.facade.UserFacade;

public class Messaging implements JabberListener{
  
  	/**
   	* The stream representing the connection to ther server
   	*/
  	private JabberStream theStream ;
  	
  	
    public static final int NO_STATE 				= -1;
    public static final int RESOURCE_BIND           = 0;
    public static final int SESSION 				= 1;		
    public static final int ONLINE 					= 2;	
    
  	private String username;
  	private String password;
  	private String domain;
  	private int state;
  	
  	private SubscriberFacade subscriberFacade;
  	private UserFacade userFacade;
  	private RssFacade rssFacade;
  	
  	public Messaging(){
  		username="";
  		password="";
  		domain="";
  		state=NO_STATE;  		
  	}
  	
	public String getUsername() {
  		return username;
	}
	
	
	public void setUsername(String username) {
		this.username = username;
	}
	
	
	public String getPassword() {
		return password;
	}


	public void setPassword(String password) {
		this.password = password;
	}
	
	
	public String getDomain() {
		return domain;
	}


	public void setDomain(String domain) {
		this.domain = domain;
	}

	
	public int getState() {
		return state;
	}
	
	public void setState(int state) {
		this.state = state;
	}
	
	
	public SubscriberFacade getSubscriberFacade() {
		if(subscriberFacade==null){
			subscriberFacade = new SubscriberFacade();
		}
		return subscriberFacade;
	}

	public UserFacade getUserFacade() {
		if(userFacade==null){
			userFacade = new UserFacade();
		}
		return userFacade;
	}

	public RssFacade getRssFacade() {
		if(rssFacade==null){
			rssFacade = new RssFacade();
		}
		return rssFacade;
	}

	/**
     * Connect to Jabber server with port 5222 and continue with user authentication
     */
    public void connect(String hostname, String username, String domain, String password, int mode) throws Exception {
    	this.username = username;
        this.domain = domain;
        this.password = password;
        
        if ((hostname != null) && (username != null) && (domain != null) &&
           (!hostname.equals("")) && (!domain.equals("")) && (!username.equals(""))) {          
               theStream = new JabberStream(new seConnector(hostname, 5222, domain));
               theStream.setJabberListener(this);
               if(mode==0)
                   registrationRequest();
               else
                   authenticationRequest();
               
       } else {
           throw(new Exception("EMPTY_FIELD"));
       }
  		
  	}
	
	/**
	 * Method to begin talking to the server (i.e. send a login message)
	 */

	public void beginConversation(){
		//registrationRequest();
		
	}
	
	public void registrationRequest() {
        try {
        Register register = new Register(username, password);
        theStream.send(register);
        } catch (IOException ex) {
            System.out.println ("No connection available");
            setState(NO_STATE);
        }
        setState(RESOURCE_BIND);
    }

    public void authenticationRequest() {
        Login login = new Login(username,password, "home");
        try {
        	theStream.send(login);
        } catch (IOException e) {
            System.out.println ("No connection available");
            setState(NO_STATE);
        }
    }
    
	

	/**
	 * Method to handle an incomming datablock.
	 *
	 * @param data The incomming data
	 */
	public void blockArrived( JabberDataBlock data ){
		try	{
			if( data instanceof Iq ){
				String type = (String) data.getAttribute ( "type" );
				
				if(getState()==RESOURCE_BIND){
					if(type.equals( "result" ) ){
						authenticationRequest();
	                    setState(SESSION);
					}else if (type.equals("error")) {                	
	                	System.out.println ("Authorization error");
	                    setState(NO_STATE);
	                    theStream.close();
	                }					
				}else if (getState()==SESSION) {
					if(type.equals( "result" ) ){
						sendPresence();
						setState(ONLINE);
						
					}else if (type.equals("error")) {                	
	                	System.out.println ("Authentication error");
	                    setState(NO_STATE);
	                    theStream.close();
	                }					
				}				
			}else if( data instanceof Message ){
				JabberDataBlock child;

				Enumeration enumeration = data.getChildBlocks().elements();
				JID from = JID.parseJIDString(data.getAttribute("from"));
	            JID to   = JID.parseJIDString(data.getAttribute("to"));
	            String temp = data.getAttribute("type");

				if (temp != null) {			
	                if (temp.equals("error")) {
	                    String errorCode = "";
	                    if (enumeration.hasMoreElements()) {
	                        child = (JabberDataBlock) enumeration.nextElement();
	                        temp = child.getTagName();
	                        if (temp.equals("error")) {
	                            errorCode = child.getAttribute("code");
	                            
	                        }
	                    }
	                    if (errorCode.equals("404")) {	// Recipient doesn't exist
							
	                    }
	                }  else {
	                    processMessage(enumeration, from, to);
	                }
	            } else {            
	                processMessage(enumeration, from, to);
	            }
			}
		}
		catch( Exception e ){
			e.printStackTrace();
		}
	}
	
	private void processMessage(Enumeration enumeration, JID from, JID to) {
		JabberDataBlock child;
		String temp;

		while (enumeration.hasMoreElements()) {
			child = (JabberDataBlock) enumeration.nextElement();
            temp = child.getTagName();
            if (temp.equals("body")) {
            	if(child.getChildBlocks()!=null){            		
            		processRSS(child, from, to);
            	}                 	
            }
		}
	}
	
	private void processRSS(JabberDataBlock child, JID from, JID to) {
		JabberDataBlock body, rss;		
		String type="", url="", id="",title="";
		Enumeration bodyEnum = child.getChildBlocks().elements();
    	if(bodyEnum.hasMoreElements()){
    		body = (JabberDataBlock) bodyEnum.nextElement();   
    		type = body.getAttribute("type");
    		
    		if(body.getTagName().equals("rss")){
    			Enumeration rssEnum = body.getChildBlocks().elements();
    			while(rssEnum.hasMoreElements()){
    				rss = (JabberDataBlock) rssEnum.nextElement();      				
    				if (rss.getTagName().equals("url")) {
						url = rss.getText();						
					}else if (rss.getTagName().equals("id")) {
						id = rss.getText();
					}else if (rss.getTagName().equals("title")) {
						title = rss.getText();
					}
    						
    			}    			
    		}     		
    	}
    	
    	if(type.equals("reg")){
    		subscribeRSSRequest(from, url, title);
    	}else if (type.equals("unreg")){
			unsubscribeRSSRequest(from, url, id);
		}
	}
	
	
	private void subscribeRSSRequest(JID from, String url, String title){
		String _username = from.username+"@"+from.domain;
		System.out.println("daftar RSS" + _username);
		String id ="";		
		if(!getUserFacade().checkUserExist(_username)){
			System.out.println("add user");
			getUserFacade().addUser(_username);			
		}
		
		if(!getRssFacade().checkRSSExist(url)){
			System.out.println("add url" + url);
			getRssFacade().addRss(url);			
		}
		if(!getSubscriberFacade().checkSubscriberExist(_username, url)){
			System.out.println("add subscriber");
			id = getSubscriberFacade().addSubscriber(_username, url);
		}
		if(id!=""){
			System.out.println("send response");
			StringBuffer response = new StringBuffer("<result type=\"reg\">");
			response.append("<id>"+id+"</id>");
			response.append("<url>"+url+"</url>");
			response.append("<title>"+title+"</title>");
			response.append("</result>");
	        
	        try {
				sendMessage(_username, response.toString());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	private void unsubscribeRSSRequest(JID from, String url, String id){
		String _username = from.username+"@"+from.domain;
		
		if(getSubscriberFacade().checkSubscriberExist(_username, url)){
			getSubscriberFacade().removeSubscriber(id);
		}		
		
		StringBuffer rssSubscriptionStreamRequest = new StringBuffer("<rss type=\"unreg_result\">");
        rssSubscriptionStreamRequest.append("<id>"+id+"</id>");
        rssSubscriptionStreamRequest.append("</rss>");
        
		
	}
	
	
	
	/**
	 * Method to inform the server we are now online
	 */

	private void sendPresence() throws IOException{
		Presence presence = new Presence();
	    theStream.send( presence );
	}
	
	
	public void sendRssResponse(String to, String message) throws IOException{
		
		StringBuffer rssSubscriptionStreamRequest = new StringBuffer("<rss type=\"reg\">");
        rssSubscriptionStreamRequest.append("<url>dada.com</url>");
        rssSubscriptionStreamRequest.append("<title>123456</title>");
        rssSubscriptionStreamRequest.append("</rss>");

		Message msg = new Message("news@mobbuzz.com", rssSubscriptionStreamRequest.toString());
		theStream.send(msg);
	}
	
	public void sendMessage(String to, String message) throws IOException{
		Message msg = new Message(to, message);
		theStream.send(msg);
	}
	/**
	 * If the connection is terminated then print a message
	 *
	 * @e The exception that caused the connection to be terminated, Note that
	 *  receiving a SocketException is normal when the client closes the stream.
	 */
	public void connectionTerminated( Exception e ){
		System.out.println( "Connection terminated" );
		if( e != null )
			e.printStackTrace();
	}



}